/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ia_0.data_model.character.move;

import ia_0.data_model.character.*;
import ia_0.data_model.character.Character;
import ia_0.data_model.map.World;
import java.awt.Point;
import java.util.HashMap;

/**
 *
 * @author jderenty
 */
public class Move {

    public Point dest;
    public Point courant;
    Character c;
    private int maxPassage=5;

    public Move(Character c, Point dest) {
        this.dest = dest;
        this.c = c;
        this.courant = World.elements.get(c);
    }
    /**
     * Renvoie null s'il est bloqué
     * @return
     */
    HashMap<Point, Integer> essayeeNb = new HashMap<Point, Integer>();

    public Point iterate() {
        if(courant.equals(dest)){
            System.out.println("ok");
            return finIterate(courant);
        }

        Point suivant=minPassage();
        
        if(seuleOption(suivant)){
            echoue(suivant);
        }


        return finIterate(suivant);
    }

    private Point finIterate(Point suivant) {
        if(suivant!=null){
            courant=suivant;
            passage(suivant);
            bouge(suivant);
        }
        return suivant;
    }

    private boolean seuleOption(Point p){
        Dir d=new Dir(courant, dest);

        Point it = d.ideale();
        while(it!=null){
            if(casePossible(courant)){
                return false;
            }
            it=d.iterate();
        }
        return true;
    }

    private Point minPassage(){
        Dir d=new Dir(courant, dest);
        Point res;
        int min=maxPassage;
        Point it = d.ideale();

        if (it.equals(dest) && !casePossible(it)){
            return null;
        }

        res=it;
        while(it!=null){
            if(casePossible(it) && min>essayeeNb(it)){
                min=essayeeNb(it);
                res=it;
            }
            it=d.iterate();
        }
        return res;
    }

    private boolean echec(Point suivant) {
        return essayeeNb(suivant)>maxPassage || essayeeNb(suivant)<0;
    }

    private boolean deja(Point suivant) {
        return essayeeNb(suivant)>0;
    }

    private void passage(Point suivant) {
        essayeeNb.put(suivant, essayeeNb(suivant)+1);
    }

    private void echoue(Point suivant) {
        essayeeNb.put(suivant, maxPassage+1);
    }

    private boolean casePossible(Point suivant) {
        return (World.free(c, suivant) && !echec(suivant));
    }

    private void bouge(Point suivant) {
        World.move(c, suivant);
    }

    private int essayeeNb(Point suivant) {
        if(essayeeNb.containsKey(suivant)){
            return essayeeNb.get(suivant);
        }
        return 0;
    }


    public Point somme(Point p1, Point p2) {
        return new Point(p1.x + p2.x, p1.y + p2.y);
    }

    class Dir extends Point {
        Point courant;
        Point dest;
        int cpt = 0;

        public Dir(Point courant,Point dest){
            this.dest=dest;
            this.courant=courant;
        }

        private Point iterate() {
            int[] liste = {1, 6, 3, 4, 5, 2, 7};
            if (cpt > 5) {
                return null;
            }
            rotate(liste[cpt]);
            cpt++;
            return somme(courant,this);

        }

        public void rotate(int nb) {
            for (int i = 0; i < nb; i++) {
                if (this.x == 1 && (this.y == 0 || this.y == 1)) {
                    this.y--;
                } else if (this.y == -1 && (this.x == 0 || this.x == 1)) {
                    this.x--;
                } else if (this.x == -1 && (this.y == 0 || this.y == -1)) {
                    this.y++;
                } else if (this.y == 1 && (this.x == 0 || this.x == -1)) {
                    this.x++;
                }
            }
        }

        private Point ideale() {

            Point dir = new Point(0, 0);
            if (courant.x < dest.x) {
                dir.x++;
            } else if (courant.x > dest.x) {
                dir.x--;
            }
            if (courant.y < dest.y) {
                dir.y++;
            } else if (courant.y > dest.y) {
                dir.y--;
            }
            this.setLocation(dir);

            return somme(courant,this);
        }

        private Point suivant(Point courant) {
            return somme(courant,courant);
        }
    }
}
